#ifndef CLICK_IGMPSTATE_H
#define CLICK_IGMPSTATE_H
#include <click/config.h>
#include <click/vector.hh>
#include <netinet/in.h>
#include "membershipreportmessage.hh"

CLICK_DECLS

/** \brief The filter mode a state is in (see rfc3376 2)
 *
 */
enum IGMPFilterMode {INCLUDE = 1, EXCLUDE = 2};

///sourceList = (sourceList + mergeSourceList)
///@return Returns if anything has changed
bool unionSourceList(Vector<in_addr>& sourceList, const Vector<in_addr>& mergeSourceList);
///sourceList = (sourceList - mergeSourceList)
///@return Returns if anything has changed        
bool differenceSourceList(Vector<in_addr>& sourceList, const Vector<in_addr>& mergeSourceList);

/** \brief Basic multicast address state (see rfc3376 3.2)   
 *
 * Maintains the most basis form of a igmp state, with a multicast address, a filter mode and a source list.
 */

class IGMPState {
    public:
        ///constructs a state with filter mode exclude and no excluded sources, which will accept any traffic
        IGMPState (const in_addr& multicastAddress);

        IGMPState (const in_addr& multicastAddress, const IGMPFilterMode& filterMode, const Vector<in_addr>&  sourceList);

        IGMPState (const in_addr& multicastAddress, const IGMPFilterMode& filterMode, int numberOfSources, in_addr* sourceList);

        ///constructs a IGMPState from it's netword representation, an IGMPGroupRecord
        IGMPState (const struct IGMPGroupRecord* groupRecord);
        
        virtual ~IGMPState ();
   
        ///merges a state with a new state (see rfc3376 6.4)
        ///@return Returns if any state schanges have taken place 
        virtual bool merge(const IGMPState& mergeState);

        ///returns if multicast traffic should be accepted from the given source or rejected 
        bool accept(const in_addr sourceAddress) const;

        ///Calculates the size of a group record representing this state
        int getGroupRecordSize() const;

        ///Copies the data from this state to the group record pointer
        ///note that this function will not allocate the memory
        ///it is the responsability of the caller to make certain it fits.
        ///You can use getGroupRecordSize to make allocate an appropriate amount
        void copyGroupRecord(struct IGMPGroupRecord* groupRecord) const;
        
        ///Returns true if the given state will accept atleast all traffic this state
        ///accepts. You can use this function to check if a received group record
        ///gave a response to a query that is also acceptable for this particular state
        bool isSuperSetOf(const IGMPState& receivedState) const;

        
    protected:    
        bool mIsSourceListSorted;
        in_addr mMulticastAddress;
        IGMPFilterMode mFilterMode;
        Vector<in_addr> mSourceList;
        
};

CLICK_ENDDECLS

#endif //CLICK_IGMPSTATE_H
